package com.event.cacheclear.handle;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.event.cacheclear.service.IBatchClearCacheService;
import com.event.common.face.IClearNameSpace;
import com.event.common.face.IEventHandle;
import com.event.common.model.UpdateAfterEvent;
import com.event.common.model.UpdateBeforeEvent;
import com.event.common.util.ThreadEventContext;
import com.event.common.util.ThreadTaskContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

/*
 * @description 更新事件句柄(这里主要是清除缓存)
 * @author Bing
 * @date 2024/10/8 13:34
 **/
@Slf4j
@Component
public class UpdateEventHandle implements IEventHandle {

    @Autowired
    @Lazy
    private IBatchClearCacheService batchClearCacheService;

    @Override
    public void handle(UpdateBeforeEvent event) {
        log.info("======> UpdateBeforeEvent : 更新事件：{}", JSONObject.toJSONString(event));
        IClearNameSpace<Object> clearNameSpace = batchClearCacheService.checkClearNameSpace(event.getAlias());
        if(Objects.isNull(clearNameSpace)){
            return;
        }
        final List<Serializable> idValues = StrUtil.isBlank(event.getIdValue()) ? new ArrayList<>() : CollUtil.toList(event.getIdValue());
        // 异步开关
        if(clearNameSpace.beforeAsync()){
            CompletableFuture<List<Serializable>> beforeFuture = CompletableFuture.supplyAsync(()->{
                return batchClearCacheService.clearCacheByIds(clearNameSpace,event.getAlias(),idValues);
            });
            ThreadTaskContext.set(beforeFuture);
            return;
        }
        // 清除缓存
        List<Serializable> busIds = batchClearCacheService.clearCacheByIds(clearNameSpace,event.getAlias(),idValues);
        ThreadEventContext.set(busIds);
    }

    @Override
    public void handle(UpdateAfterEvent event) {
        try {
            log.info("======> UpdateAfterEvent : 更新事件：{}", JSONObject.toJSONString(event));
            IClearNameSpace<Object> clearNameSpace = batchClearCacheService.checkClearNameSpace(event.getAlias());
            if(Objects.isNull(clearNameSpace)){
                return;
            }
            // 异步开关
            if(clearNameSpace.afterAsync()){
                CompletableFuture<List<Serializable>> beforeFuture = ThreadTaskContext.get();
                // 判断当前是否有事务
                if(TransactionSynchronizationManager.isActualTransactionActive()){
                    TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                        @Override
                        public void afterCommit() {
                            beforeFuture.thenAcceptAsync(busIds->{
                                clearCache(clearNameSpace, event.getAlias(), event.getIdValue(), busIds);
                            });
                        }
                    });
                }else{
                    beforeFuture.thenAcceptAsync(busIds->{
                        clearCache(clearNameSpace, event.getAlias(), event.getIdValue(), busIds);
                    });
                }
                return;
            }
            // 清除缓存
            List<Serializable> busIds = ThreadEventContext.get();
            clearCache(clearNameSpace, event.getAlias(), event.getIdValue(), busIds);
        }finally {
            ThreadTaskContext.remove();
            ThreadEventContext.remove();
        }
    }

    /**
     * 清除缓存
     * @param clearNameSpace
     * @param alias
     * @param idValue
     * @param busIds
     */
    private void clearCache(IClearNameSpace<Object> clearNameSpace,String alias,String idValue,List<Serializable> busIds){
        if(CollUtil.isEmpty(busIds) && StrUtil.isNotBlank(idValue)){
            batchClearCacheService.clearCacheByIds(clearNameSpace,alias, CollUtil.toList(idValue));
            return;
        }
        batchClearCacheService.clearCache(alias, busIds);
    }
}
